using System;
using System.Collections.Generic;
using SCG.SolarVengeanceEngine;
using SCG.SolarVengeanceEngine.BrainInfo;

namespace SCG.SolarVengeance.Brains
{
    public class Argus : Brain
    {
        //select starships
        public override List<StarShipType> AvailableShipTypes
        {
            get
            {
                List<StarShipType> avail = new List<StarShipType>();
                avail.Add(StarShipType.WarShip);
                avail.Add(StarShipType.Drone);
                avail.Add(StarShipType.EMine);
                avail.Add(StarShipType.InkSpot);
                avail.Add(StarShipType.ScanShip);
                avail.Add(StarShipType.StarTillery);
                return avail;
            }
        }

        //difficulty
        public override ChallengeLevel Challenge
        {
            get
            {
                return ChallengeLevel.Easy;
            }
        }

        //primary Brain logic
        public override void Execute()
        {
            //Count starship types we have
            int warships = 0;
            int drones = 0;
            int inkspots = 0;
            foreach (StarShipInfo ship in MyStarShips)
            {
                if (ship.ShipType == StarShipType.WarShip)
                    warships++;
                else if (ship.ShipType == StarShipType.Drone)
                    drones++;
                else if (ship.ShipType == StarShipType.InkSpot)
                    inkspots++;
            }

            //Count our starsystems, and remember value of all visible ones - weight capitals higher
            int systems = 0;
            foreach (StarSystemInfo system in StarSystems)
            {
                if (system.OwnedByMe)
                    systems++;
                if (system.Visible)
                {
                    int weight = system.Value;
                    if (system.IsCapital)
                        weight += 5;
                    _systemValues[system.Name] = weight;                  
                }
            }

            //Give orders to owned starsystems
            StarSystemInfo capital = null;
            bool capitalThreatened = false;
            int capx = 0;
            int capy = 0;
            foreach(StarSystemInfo system in StarSystems)
                if (system.OwnedByMe)
                {
                    //see if capital is threatened
                    if (system.IsCapital)
                    {
                        capital = system;
                        capx = system.X;
                        capy = system.Y;
                        capitalThreatened = ClosestStarShip(system.X, system.Y, 5, FindShipFlags.Enemy, ShipKnownFlags.Either) != null;
                    }

                    //make sure it has adaquate shields
                    bool buildShields = system.IsCapital;
                    if (!buildShields)
                        buildShields = ClosestStarShip(system.X, system.Y, 12, FindShipFlags.Enemy, ShipKnownFlags.Either) != null;
                    if (buildShields && system.Shields < system.Value / 2)
                        BuildShields(system, 5);

                    //build StarTillery
                    if (system.Resources > 100)
                        if (Random(1, 10) > 5)
                            BuildStarShip(system, StarShipType.StarTillery, Random(8, 15), Random(4, 8), false);

                    //build ScanShip
                    if (system.Resources > 100)
                        if (Random(1, 10) > 7)
                            BuildStarShip(system, StarShipType.ScanShip, Random(8, 20), Random(4, 10), false);

                    //Build InkSpots or Drones
                    if (warships >= systems)
                    {
                        if (Random(1, 10) > 5)
                            if (inkspots * 2 < warships)
                                BuildStarShip(system, StarShipType.InkSpot, Random(5, 12), 0, false);
                        if (Random(1, 10) > 5)
                            if (drones * 2 < warships)
                                BuildStarShip(system, StarShipType.Drone, Random(5, 15), 0, false);
                    }

                    //Build WarShips
                    if (system.Resources < 12 && warships < systems)
                        BuildStarShip(system, StarShipType.WarShip, Random(4, 6), Random(2, 3), false);
                    else
                    {
                        int num = system.Resources / 30;
                        while (num > 0)
                        {
                            BuildStarShip(system, StarShipType.WarShip, Random(6, 20), Random(3, 20), false);
                            num--;
                        }
                    }

                    //If we happen to be able to, build a TechShip
                    if (warships >= systems)
                        if (system.Resources > 300)
                            BuildStarShip(system, StarShipType.TechShip, 3, 0, false);

                    //Build EMines
                    if (warships >= systems)
                        if (Random(1, 10) > 8)
                            BuildStarShip(system, StarShipType.EMine, 1, 0, false);
                }

            //Give StarShips orders
            foreach (StarShipInfo ship in MyStarShips)
            {
                switch (ship.ShipType)
                {
                    case StarShipType.InkSpot:
                        //InkSpots will swarm the closest enemy StarShip or StarSystem ... if none is found, they go to the closest unowned StarSystem
                        StarShipInfo target = ClosestStarShip(ship.X, ship.Y, Int32.MaxValue, FindShipFlags.Enemy, ShipKnownFlags.Unknown);
                        if (target != null)
                            Target(ship, target);
                        else
                        {
                            StarSystemInfo targetSys = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Unfriendly);
                            if (targetSys != null)
                                Move(ship, targetSys.X + Random(-4, 4), targetSys.Y + Random(-4, 4));
                            else
                                Move(ship, ship.X + Random(-4, 4), ship.Y + Random(-4, 4));
                        }
                        break;
                    case StarShipType.ScanShip:
                        //ScanShips will attempt to spot the closest non-visible StarSystem
                        StarSystemInfo sysScan = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.NonVisible);
                        if (sysScan != null)
                            Move(ship, sysScan.X + Random(-3, 3), sysScan.Y + Random(-3, 3));
                        else
                            Move(ship, ship.X + Random(-8, 8), ship.Y + Random(-8, 8));
                        break;
                    case StarShipType.Drone:
                        //Drones defend the closest friendly StarSystem
                        StarShipInfo shipTarget = ClosestStarShip(ship.X, ship.Y, Int32.MaxValue, FindShipFlags.Enemy, ShipKnownFlags.Either);
                        if (shipTarget != null)
                            Target(ship, shipTarget);
                        else
                        {
                            StarSystemInfo sysTarget = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Owned);
                            if (sysTarget != null)
                            {
                                if (DistanceQuick(ship.X, ship.Y, sysTarget.X, sysTarget.Y) < 3)
                                    Move(ship, ship.X + Random(-10, 10), ship.Y + Random(-10, 10));
                                else
                                    Defend(ship, sysTarget);
                            }
                        }
                        break;
                    case StarShipType.TechShip:
                        //Get TechShips out of the way
                        int dx = ship.X < MapWidth / 2 ? 0 : MapWidth - 1;
                        int dy = ship.Y < MapHeight / 2 ? 0 : MapHeight - 1;
                        Move(ship, dx, dy);
                        break;
                    case StarShipType.EMine:
                        //Slowly move EMines toward enemy/unknown StarSystems
                        StarSystemInfo emineTarg = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.VisibleUnfriendly);
                        if (emineTarg != null)
                            Move(ship, emineTarg.X, emineTarg.Y);
                        break;
                    case StarShipType.StarTillery:
                        //Startillery tries to pick off enemy ships while maintaining distance
                        if (capitalThreatened)
                            Move(ship, capx + Random(-4, 4), capy + Random(-4, 4));
                        else
                        {
                            StarShipInfo stTarg = ClosestStarShip(ship.X, ship.Y, Int32.MaxValue, FindShipFlags.Enemy, ShipKnownFlags.Either);
                            if (stTarg != null)
                                Move(ship, stTarg.X + Random(-4, 4), stTarg.Y + Random(-4, 4));
                            else
                                Move(ship, ship.X + Random(-10, 10), ship.Y + Random(-10, 10));
                        }
                        break;
                    default:
                        //WarShips will attack enemies if Weapons > 3, and will attack the most valuable StarSystem.  If the capital is threatned, strong WarShips will defend it
                        AttackAdjacent(ship, ship.Value > 3);
                        if (capitalThreatened && ship.Value > 5 && DistanceQuick(ship.X, ship.Y, capx, capy) < 30)
                            Defend(ship, capital);
                        else
                        {
                            StarSystemInfo sysTarget = ClosestStarSystem(ship.X, ship.Y, 2, FindSystemFlags.Enemy);
                            if (sysTarget != null)
                                Target(ship, sysTarget);
                            else
                            {
                                sysTarget = null;
                                int highestWeight = Int32.MinValue;
                                foreach (StarSystemInfo sys in StarSystems)
                                {
                                    if (sys.OwnedByMe)
                                        continue;

                                    //Lookup the weight of the StarSystem
                                    int weight = 3;
                                    if (_systemValues.ContainsKey(sys.Name))
                                        weight = _systemValues[sys.Name];

                                    //weight value against distance
                                    weight *= 10;
                                    weight -= DistanceQuick(ship.X, ship.Y, sys.X, sys.Y);
                                    if (weight > highestWeight)
                                    {
                                        highestWeight = weight;
                                        sysTarget = sys;
                                    }
                                }
                                if (sysTarget == null)
                                    sysTarget = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Unfriendly);
                                if (sysTarget != null)
                                    Target(ship, sysTarget);
                                else
                                    Defend(ship, ship);
                            }
                        }
                        break;
                }
            }
        }

        //Argus description
        public override string Description
        {
            get
            {
                return "Argus was a mythological monster with 1,000 eyes.  This Brain uses numerous InkSpots to tag enemy StarShips, StarTillery to destroy them, and ScanShips to explore.  It has an advanced ScanShip algorithm, and won't get stuck in Nebula.  Also, it remembers the values of StarSystems that it encounters.";
            }
        }

        //private members
        private Dictionary<string, int> _systemValues = new Dictionary<string, int>();
    }
}
